package com.yuyou.fn.educational.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.wens.mq.MessageHandler;
import com.github.wens.mq.RedisMessageQueue;
import com.github.wens.mybatisplus.examples.Example;
import com.github.wens.mybatisplus.plugins.Page;
import com.github.wens.mybatisplus.toolkit.IdWorker;
import com.yuyou.fn.common.exception.BusException;
import com.yuyou.fn.common.util.BeanUtils;
import com.yuyou.fn.common.util.JSONS;
import com.yuyou.fn.common.util.TimeUtils;
import com.yuyou.fn.common.util.Utils;
import com.yuyou.fn.educational.entity.CourseClass;
import com.yuyou.fn.educational.entity.Student;
import com.yuyou.fn.educational.entity.StudentReg;
import com.yuyou.fn.educational.service.*;
import com.yuyou.fn.educational.vo.RegClassInfoVo;
import com.yuyou.fn.educational.vo.StudentRegInfoVo;
import com.yuyou.fn.settlement.service.ISettlementService;
import org.springframework.stereotype.Service;

import com.yuyou.fn.educational.mapper.CourseOrderMapper;
import com.yuyou.fn.educational.entity.CourseOrder;
import com.github.wens.framework.service.impl.SuperServiceImpl;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * CourseOrder 表数据服务层接口实现类
 */
@Service
public class CourseOrderServiceImpl extends SuperServiceImpl<CourseOrderMapper, CourseOrder, Long> implements ICourseOrderService {

    @Resource
    private IStudentRegService studentRegService;

    @Resource
    private ICourseClassService courseClassService ;

    @Resource
    private IStudentService studentService ;

    @Resource
    private IPayRecordService payRecordService ;

    @Resource
    private ISettlementService settlementService;

    @Resource
    private RedisMessageQueue redisMessageQueue ;

    @PostConstruct
    public void init(){
        redisMessageQueue.consume("order:pay:success:courseOrder", new MessageHandler() {
            @Override
            public void onMessage(byte[] bytes) {
                JSONObject jsonObject = JSONS.toJSONObject(bytes);
                Long courseOrderId  = jsonObject.getLong("busId");
                BigDecimal amount = jsonObject.getBigDecimal("amount");
                CourseOrderServiceImpl.this.payCourseOrder(courseOrderId,amount,4,null);
            }
        });
    }


    @Override
    public Page<CourseOrder> findCourseOrderList(Long studentId, int pageNo, int pageSize) {
        Example<CourseOrder> example = CourseOrder.createExample();
        example.orderBy("createTime").desc();
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("studentId" , studentId ) ;
        return findPageByExample(example, pageNo, pageSize);
    }

    @Transactional
    @Override
    public void payCourseOrder(Long courseOrderId, BigDecimal payAmount, Integer payWay , String operator) {

        CourseOrder courseOrder = findById(courseOrderId);

        if( 2 == courseOrder.getChargingStatus() ){
            return  ;
        }

        BigDecimal owing = courseOrder.getPayableAmount().subtract(courseOrder.getPaidAmount());
        if(payAmount.doubleValue() > owing.doubleValue()  ){
            throw new BusException("支付金额大于应付金额");
        }

        //账户余额,检查余额是否足够
        if(3 == payWay ){
            settlementService.decreaseBalance(courseOrder.getStudentId(),payAmount) ;
        }

        CourseOrder updateCourseOrder = new CourseOrder();
        updateCourseOrder.setCourseOrderId(courseOrderId);
        updateCourseOrder.setPaidAmount(payAmount);
        updateCourseOrder.setPaidAmount(courseOrder.getPaidAmount().add(payAmount));
        if( (long)( courseOrder.getPayableAmount().doubleValue() * 100 ) == (long)(updateCourseOrder.getPaidAmount().doubleValue() * 100 )  ){
            updateCourseOrder.setChargingStatus(2);
        }else{
            updateCourseOrder.setChargingStatus(1);
        }
        updateSelectiveById(updateCourseOrder);

        payRecordService.savePayRecord(courseOrderId,payAmount ,payWay , operator ) ;
        studentRegService.changeStudentRegCharging( courseOrderId , courseOrder.getPayableAmount() , updateCourseOrder.getPaidAmount() , updateCourseOrder.getChargingStatus() );


        //结算
        List<StudentReg> studentRegList = studentRegService.findStudentRegByCourseOrderId(courseOrderId);

        for(StudentReg studentReg : studentRegList ){
            BigDecimal amount = studentReg.getChargingStatus() == 2 ? studentReg.getTotalAmount() : Utils.calProportion(payAmount, studentReg.getTotalAmount() , courseOrder.getPayableAmount() );
            settlementService.increaseBalance(studentReg.getStudentId(),amount);
            settlementService.bookIncomeForCourse(studentReg.getFinancialOwnerId() ,studentReg.getStudentId() , amount , studentReg.getClassName(), studentReg.getClassId() , studentReg.getRegId()   ) ;
        }

    }


    @Transactional
    @Override
    public CourseOrder createOrder(StudentRegInfoVo studentRegInfoVo) {
        CourseOrder courseOrder = new CourseOrder();
        courseOrder.setCourseOrderId(IdWorker.getId());
        courseOrder.setCreateTime(TimeUtils.now());
        courseOrder.setUpdateTime(TimeUtils.now());
        courseOrder.setStudentId(studentRegInfoVo.getStudentId());
        courseOrder.setRegFrom(studentRegInfoVo.getFrom());

        Map<Long,RegClassInfoVo> regClassInfoMap = BeanUtils.toMap( studentRegInfoVo.getRegClassInfoList() , "classId");
        List<CourseClass> courseClassList = courseClassService.findByIds(new ArrayList<Long>(regClassInfoMap.keySet()));

        Student student = studentService.findById(studentRegInfoVo.getStudentId());
        courseOrder.setStudentName(student.getName()==null?null:student.getName());
        List<StudentReg> studentRegList = new ArrayList<>(courseClassList.size());
        BigDecimal orderMoney = new BigDecimal(0);
        for(CourseClass courseClass : courseClassList ){

            if(courseClass.getRegAmount().intValue() >= courseClass.getQuota().intValue()){
                throw new BusException("【"+courseClass.getClassName()+"】学位已经报满") ;
            }

            if(studentRegService.hadReg(courseClass.getClassId(),studentRegInfoVo.getStudentId())){
                throw new BusException(student.getName()+"已经报名过【"+courseClass.getClassName()+"】") ;
            }

            if( !courseClassService.increaseRegAmount(courseClass.getClassId(),courseClass.getRegAmount())){
                throw new BusException("报名失败，请重试!") ;
            }

            RegClassInfoVo regClassInfoVo = regClassInfoMap.get(courseClass.getClassId());
            StudentReg studentReg = new StudentReg();
            studentReg.setCourseOrderId(courseOrder.getCourseOrderId());
            studentReg.setClassId(courseClass.getClassId());
            studentReg.setClassName(courseClass.getClassName());
            studentReg.setCreateTime(TimeUtils.now());
            studentReg.setUpdateTime(TimeUtils.now());
            studentReg.setStartAmount(regClassInfoVo.getStartAmount());
            studentReg.setEndAmount(regClassInfoVo.getEndAmount());
            studentReg.setRegFrom(studentRegInfoVo.getFrom());//线下
            studentReg.setChargingStatus(0);
            studentReg.setRegStatus(0);
            studentReg.setPayAmount(BigDecimal.valueOf(0));
            studentReg.setStudentId(student.getStudentId());
            studentReg.setStudentName(student.getName());
            studentReg.setFinancialOwnerId(courseClass.getBusTeamId());
            studentReg.setAreaTeamId(courseClass.getAreaTeamId());
            studentReg.setBusTeamId(courseClass.getBusTeamId());

            int lectureAmount = regClassInfoVo.getEndAmount() - regClassInfoVo.getStartAmount() + 1 ;
            if(lectureAmount == courseClass.getLectureAmount() ){
                studentReg.setTotalAmount(courseClass.getStudyingFee());
            }else{
                //计算比例
                studentReg.setTotalAmount( Utils.calProportion( courseClass.getStudyingFee() ,new BigDecimal(lectureAmount) , new BigDecimal(courseClass.getLectureAmount()) ));
            }

            orderMoney = orderMoney.add(studentReg.getTotalAmount());
            studentRegList.add(studentReg) ;
        }
        studentRegService.saveStudentReg(studentRegList) ;
        courseOrder.setTotalAmount(orderMoney);
        courseOrder.setPayableAmount(orderMoney);
        insertSelective(courseOrder);
        return courseOrder ;
    }

    public List<CourseOrder> findBaseCourseOrderForList(Long studentId) {
        Example<CourseOrder> example = CourseOrder.createExample();
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("studentId", studentId);
        return findListByExample(example);
    }

    @Override
    public List<CourseOrder> findCourseOrderByOutId(Long outerCourseOrderId) {
        Example<CourseOrder> example = CourseOrder.createExample();
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("outerCourseOrderId", outerCourseOrderId);
        return findListByExample(example);

    }
}